話說鐵人賽每到晚上11點過後,如果還沒想到今天的發文內容,那真的是分秒必爭,
就來舉個"分秒必爭嗎?"的話題吧!
每天刷卡上下班,如何找出遲到10分鐘內的名單
例如: 8點上班,8:01:00 - 8:10:59算遲到,之後的一律請假
網路看到很多在寫這類條件的問答,很多都是這麼寫的
where card_datetime >= to_date('2013/10/05 08:01:00', 'yyyy/mm/dd hh24:mi:ss')
and card_datetime <= to_date('2013/10/05 08:09:59', 'yyyy/mm/dd hh24:mi:ss')
來測試看看
create table ithelp_cards
(card_no number,
card_datetime date);
insert into ithelp_cards values(10001, to_date('20131005 080059', 'yyyymmdd hh24miss'))
....
檢查資料
select card_no, to_char(card_datetime, 'yyyy/mm/dd hh24:mi:ss') card_datetime
from ithelp_cards
共4筆
CARD_NO CARD_DATETIME
--------- -----------------------------------------------------------
10001 2013/10/05 08:00:59
10002 2013/10/05 08:01:00
10003 2013/10/05 08:09:59
10004 2013/10/05 08:10:00
select card_no, to_char(card_datetime, 'yyyy/mm/dd hh24:mi:ss') card_datetime
from ithelp_cards
where card_datetime >= to_date('2013/10/05 08:01:00', 'yyyy/mm/dd hh24:mi:ss')
and card_datetime <= to_date('2013/10/05 08:09:59', 'yyyy/mm/dd hh24:mi:ss')
結果沒錯
CARD_NO CARD_DATETIME
--------- -------------------------------------------------------
10002 2013/10/05 08:01:00
10003 2013/10/05 08:09:59
那,當你要抓的是整個月呢?
再補兩筆來測試
CARD_NO CARD_DATETIME
10001 2013/10/05 08:00:59
10002 2013/10/05 08:01:00
10003 2013/10/05 08:09:59
10004 2013/10/05 08:10:00
10001 2013/10/04 08:10:00
10002 2013/10/04 08:00:00
結果是這種單一日寫法變得無法處理了,必須改寫
where card_datetime >= to_date('2013/10/01 08:01:00', 'yyyy/mm/dd hh24:mi:ss')
and card_datetime <= to_date('2013/10/31 08:09:59', 'yyyy/mm/dd hh24:mi:ss')
那要寫多少條件?我不想用上面SQL改寫....
那試試這個做法吧!
先觀察資料,Date or datetime 在oracle都可以直接拿來加減的,
把她扣掉她自己的純日期,會得到刷卡時間的日數(0~1),trunc可不加’dd’,習慣補上
1 select card_no
2 , substrb(to_char(card_datetime, 'yyyy/mm/dd hh24:mi:ss'), 1, 25) card_datetime
3 , card_datetime - trunc(card_datetime , 'dd') days
4 from ithelp_cards
5 where card_datetime >= to_date('2013/10/01', 'yyyy/mm/dd')
6 and card_datetime <= to_date('2013/10/31', 'yyyy/mm/dd')
7* and card_datetime - trunc(card_datetime , 'dd') > 0
CARD_NO CARD_DATETIME DAYS
--------- ------------------------- ---------
10001 2013/10/05 08:00:59 .3340162
10002 2013/10/05 08:01:00 .33402778
10003 2013/10/05 08:09:59 .3402662
10004 2013/10/05 08:10:00 .34027778
10001 2013/10/04 08:10:00 .34027778
10002 2013/10/04 08:00:00 .33333333
發現兩個門檻,分別是
08:01:00 .33402778
08:09:59 .3402662
所以加上這個門檻,因為日數算到1秒,會有很多小數位後看不到被進位的小差異,會影響結果,
可斟酌進位到5位小數即可。
1 select card_no
2 , substrb(to_char(card_datetime, 'yyyy/mm/dd hh24:mi:ss'), 1, 25) card_datetime
3 , card_datetime - trunc(card_datetime, 'dd') days
4 from ithelp_cards
5 where card_datetime >= to_date('2013/10/01', 'yyyy/mm/dd')
6 and card_datetime <= to_date('2013/10/31', 'yyyy/mm/dd')
7 and card_datetime - trunc(card_datetime , 'dd') > 0.33402
8* and card_datetime - trunc(card_datetime , 'dd') < 0.34027
CARD_NO CARD_DATETIME DAYS
--------- ------------------------- ---------
10002 2013/10/05 08:01:00 .33402778
10003 2013/10/05 08:09:59 .3402662
另外,小時差可以直接用 1/24 ~ 2/24 方式表示1點到2點,
包含上述條件,也可以用 (8*60*60 sec + 1*60 sec) / 86400 sec
= 0.3340277777777778 天
這兩句就會變成這樣
and card_datetime - trunc(card_datetime , 'dd') > (8*6*60 + 1*60 + 0)/86400 --8:01:00
and card_datetime - trunc(card_datetime , 'dd') < (8*6*60 + 10*60 + 0)/86400 --8:10:00
雖然俗話說:要怎麼收穫就怎麼栽...
但我還是那句話,看到"那種"條件未必要用"那種"方式解答,僅供參考!
[開發技術組]全文閱讀
http://ithelp.ithome.com.tw/ironman6/player/yafuu168/dev/1
[鐵人人生組]全文閱讀
http://ithelp.ithome.com.tw/ironman6/player/yafuu168/life/1
終於邁向倒數10天,很辛苦的自己挑戰,
後面有時間的話,想做一隻小遊戲,時間不夠,就等完結後再來POST。
加油!